//
//  cookies.h
//
//  Created by harrse on 5/5/17.
//  Copyright 2017 harrse. All rights reserved.
//

#ifndef __diylane_cookies_h
#define __diylane_cookies_h

#include <string>
#include <unordered_map>
#include "boost/lexical_cast.hpp"

#include "utilities.hpp"

namespace diylane {
namespace http {

struct Cookie {
    std::string name;
    std::string value;
    uint64_t expires = 0;
    int64_t max_age = -1;
    std::string domain = "";
    std::string path = "";
    bool secure = false;
    bool http_only = false;

    Cookie(const char* _name = "", const char* _value = "") {
        name = _name;
        value = _value;
    }

    ~Cookie() {}

    std::string to_SetCookie() {
        std::string str;
        str += name + "=" + value;
        if (domain.length()) {
            str += "; Domain=";
            str += domain;
        }
        if (path.length()) {
            str += "; Path=";
            str += path;
        }
        if (expires) {
            str += "; Expires=";
            str += expires;
        }
        if (max_age >= 0) {
            str += "; Max-Age=";
            std::string maxAge = boost::lexical_cast<std::string>(max_age);
            str += maxAge;
        }
        if (secure) {
            str += "; Secure";
        }
        if (http_only) {
            str += "; HttpOnly";
        }
        return str;
    }

    std::string to_Cookie() {
        std::string str;
        str += name + "=" + value + ";";
        return str;
    }

};

typedef std::unordered_map<std::string, Cookie*> Cookies;

struct CookieJar {
    Cookies cookies;

    CookieJar() {

    }

    ~CookieJar() {
        Cookies::iterator iCookie;
        for (iCookie = cookies.begin(); iCookie != cookies.end(); iCookie++) {
            delete iCookie->second;
        }
    }

    void set(Cookie* c) {
        cookies[c->name] = c;
    }

    std::string cookieString() {
        std::string buffer = "";
        Cookies::iterator iCookie;
        for (iCookie = cookies.begin(); iCookie != cookies.end(); iCookie++) {
            if (buffer.length()>0) {
                buffer+=" ";
            }
            buffer+=iCookie->second->to_Cookie();
        }
        return buffer;
    }

    Cookie* get(const char* name) {
        Cookies::iterator iCookie = cookies.find(name);
        if (iCookie != cookies.end()) {
            return iCookie->second;
        }
        return NULL;
    }

    bool parse(std::string cookieString) {
        size_t len = cookieString.length();
        char* buf = (char*)malloc(len + 1);
        if (buf == 0) {
            return false;
        }
#ifdef _MSC_VER
        strcpy_s(buf, len + 1, cookieString.c_str());
#else
        strcpy(buf, cookieString.c_str());
#endif
        char *p = buf;
        while ((size_t)(p-buf) < len) {
            char* seg = p;
            char* delimiter = strchr(seg, ';');
            if (delimiter == 0) {
                delimiter = seg + strlen(seg);
            }
            *delimiter = '\0';
            p = delimiter + 1;
            size_t seglen = strlen(seg);
            char* name = seg;
            name = util::S::trimL(name);
            delimiter = strchr(name, '=');
            if (delimiter == 0) {
                delimiter = name + strlen(name);
            }
            *delimiter = '\0';
            char* value = delimiter + 1;
            if ((size_t)(value - seg) < seglen) {
                value = util::S::trimL(value);
            }
            else {
                value = (char*)"";
            }
            util::S::trimR(name);
            util::S::trimR(value);
            set(new Cookie(name, value));
        }
        free(buf);
        return true;
    }

};

}
}

#endif
